<template>
    <div class="">
        <div class="left" style="margin-right: 40px">
            <el-button @click="runCase" :loading="caseLoading" type="success">
                运行用例
            </el-button>
            <el-button @click="downloadYaml" type="primary">
                下载yaml
            </el-button>
            <el-button
                style="margin-right: 12px"
                @click="drawer = true"
                type="primary">
                查看日志
            </el-button>
            <el-upload
                :show-file-list="false"
                :on-success="uploadSuccess"
                :on-error="uploadError"
                :action="baseUrl + '/uploadDebugtalk'">
                <el-button type="primary">上传debugtalk</el-button>
            </el-upload>
        </div>
        <el-collapse>
            <div class="collapse-item">
                <div class="collapse-item-container">
                    <el-collapse-item title="Config" name="2">
                        <div class="item">
                            <div class="title left">用例名:</div>
                            <el-input
                                v-model="config.name"
                                style="width: 240px"
                                placeholder="用例名" />
                        </div>
                        <div class="item">
                            <div class="title left">base-url:</div>
                            <el-input
                                v-model="config.base_url"
                                style="width: 240px"
                                placeholder="域名" />
                        </div>
                        <div class="item">
                            <div class="title left">HTTPS:</div>
                            <el-select
                                class="select-width"
                                v-model="config.verify"
                                placeholder="HTTPS验证">
                                <el-option
                                    v-for="item in isHttps"
                                    :key="item"
                                    :label="item"
                                    :value="item">
                                </el-option>
                            </el-select>
                        </div>
                        <div class="list">
                            <div class="left title">设置变量</div>
                            <div
                                class="left li-item"
                                v-for="(variable, index) in config.variableList"
                                :key="index">
                                <li>
                                    <el-input
                                        v-model="variable.name"
                                        style="width: 80px"
                                        placeholder="变量名" />:
                                    <el-input
                                        v-model="variable.value"
                                        style="width: 240px; margin-right: 5px"
                                        placeholder="变量值" />
                                    <el-button
                                        v-if="
                                            index ==
                                            config.variableList.length - 1
                                        "
                                        type="primary"
                                        @click="addParam(config.variableList)"
                                        >添加</el-button
                                    >
                                    <el-button
                                        type="danger"
                                        @click="
                                            delParam(config.variableList, index)
                                        "
                                        >删除</el-button
                                    >
                                </li>
                            </div>
                            <el-button
                                class="left"
                                v-if="config.variableList.length == 0"
                                type="primary"
                                @click="addParam(config.variableList)"
                                >添加</el-button
                            >
                        </div>
                        <div class="list">
                            <div class="left title">导出全局变量</div>
                            <div
                                class="left li-item"
                                v-for="(eName, index) in config.export"
                                :key="index">
                                <li>
                                    <el-input
                                        v-model="config.export[index]"
                                        style="width: 80px; margin-right: 5px"
                                        placeholder="变量名" />
                                    <el-button
                                        v-if="index == config.export.length - 1"
                                        type="primary"
                                        @click="addExport(config.export)"
                                        >添加</el-button
                                    >
                                    <el-button
                                        type="danger"
                                        @click="delParam(config.export, index)"
                                        >删除</el-button
                                    >
                                </li>
                            </div>
                            <el-button
                                class="left"
                                v-if="config.export.length == 0"
                                type="primary"
                                @click="addExport(config.export)"
                                >添加</el-button
                            >
                        </div>
                    </el-collapse-item>
                </div>
                <div class="button-container">
                    <div class="but-item">
                        <el-button type="success" @click="updateConfig()"
                            >更新配置</el-button
                        >
                    </div>
                </div>
            </div>
            <!-- 步骤 -->
            <div
                class="collapse-item"
                v-for="(step, index) in steps"
                :key="index">
                <div class="collapse-item-container">
                    <el-collapse-item :title="'STEP' + (index + 1)">
                        <div class="item">
                            <div class="title left">步骤名:</div>
                            <el-input
                                v-model="step.name"
                                style="width: 240px"
                                placeholder="步骤名" />
                        </div>
                        <div class="list">
                            <div class="title left">设置变量</div>
                            <div
                                class="left li-item"
                                v-for="(variable, index) in step.variableList"
                                :key="index">
                                <li>
                                    <el-input
                                        v-model="variable.name"
                                        style="width: 80px"
                                        placeholder="变量名" />:
                                    <el-input
                                        v-model="variable.value"
                                        style="width: 240px; margin-right: 5px"
                                        placeholder="变量值" />
                                    <el-button
                                        v-if="
                                            index ==
                                            step.variableList.length - 1
                                        "
                                        type="primary"
                                        @click="addParam(step.variableList)"
                                        >添加</el-button
                                    >
                                    <el-button
                                        type="danger"
                                        @click="
                                            delParam(step.variableList, index)
                                        "
                                        >删除</el-button
                                    >
                                </li>
                            </div>
                            <el-button
                                class="left"
                                v-if="step.variableList.length == 0"
                                type="primary"
                                @click="addParam(step.variableList)"
                                >添加</el-button
                            >
                        </div>
                        <div class="item" style="flex-direction: column">
                            <div class="title left">请求配置:</div>

                            <div class="item li-item">
                                <div class="title left">请求方法:</div>
                                <el-select
                                    class="select-width"
                                    v-model="step.request.method"
                                    placeholder="请求方法">
                                    <el-option
                                        v-for="item in MethodOptions"
                                        :key="item"
                                        :label="item"
                                        :value="item">
                                    </el-option>
                                </el-select>
                            </div>
                            <div class="item">
                                <div class="title left">接口url:</div>
                                <el-input
                                    v-model="step.request.url"
                                    style="width: 240px"
                                    placeholder="url" />
                            </div>
                            <div class="list">
                                <div class="title left">headers</div>
                                <div
                                    class="left li-item"
                                    v-for="(header, index) in step.request
                                        .headerList"
                                    :key="index">
                                    <li>
                                        <el-input
                                            v-model="header.name"
                                            style="width: 80px"
                                            placeholder="变量名" />:
                                        <el-input
                                            v-model="header.value"
                                            style="
                                                width: 240px;
                                                margin-right: 5px;
                                            "
                                            placeholder="变量值" />
                                        <el-button
                                            v-if="
                                                index ==
                                                step.request.headerList.length -
                                                    1
                                            "
                                            type="primary"
                                            @click="
                                                addParam(
                                                    step.request.headerList
                                                )
                                            "
                                            >添加</el-button
                                        >
                                        <el-button
                                            type="danger"
                                            @click="
                                                delParam(
                                                    step.request.headerList,
                                                    index
                                                )
                                            "
                                            >删除</el-button
                                        >
                                    </li>
                                </div>
                                <el-button
                                    class="left"
                                    v-if="step.request.headerList.length == 0"
                                    type="primary"
                                    @click="addParam(step.request.headerList)"
                                    >添加</el-button
                                >
                            </div>
                            <div class="list">
                                <div class="title left">cookies</div>
                                <div
                                    class="left li-item"
                                    v-for="(cookie, index) in step.request
                                        .cookieList"
                                    :key="index">
                                    <li>
                                        <el-input
                                            v-model="cookie.name"
                                            style="width: 80px"
                                            placeholder="变量名" />:
                                        <el-input
                                            v-model="cookie.value"
                                            style="
                                                width: 240px;
                                                margin-right: 5px;
                                            "
                                            placeholder="变量值" />
                                        <el-button
                                            v-if="
                                                index ==
                                                step.request.cookieList.length -
                                                    1
                                            "
                                            type="primary"
                                            @click="
                                                addParam(
                                                    step.request.cookieList
                                                )
                                            "
                                            >添加</el-button
                                        >
                                        <el-button
                                            type="danger"
                                            @click="
                                                delParam(
                                                    step.request.cookieList,
                                                    index
                                                )
                                            "
                                            >删除</el-button
                                        >
                                    </li>
                                </div>
                                <el-button
                                    class="left"
                                    v-if="step.request.cookieList.length == 0"
                                    type="primary"
                                    @click="addParam(step.request.cookieList)"
                                    >添加</el-button
                                >
                            </div>
                            <div id="requestData">
                                <el-radio-group v-model="step.paramRadio">
                                    <el-radio :value="1">表单</el-radio>
                                    <el-radio :value="2">JSON</el-radio>
                                    <el-radio :value="3">params</el-radio>
                                </el-radio-group>
                                <div class="params" v-if="step.paramRadio == 1">
                                    <div
                                        class="left"
                                        v-for="(data, index) in step.request
                                            .dataList"
                                        :key="index">
                                        <el-input
                                            v-model="data.name"
                                            style="width: 80px"
                                            placeholder="变量名" />:
                                        <el-input
                                            v-model="data.value"
                                            style="
                                                width: 240px;
                                                margin-right: 5px;
                                            "
                                            placeholder="变量值" />
                                        <el-button
                                            v-if="
                                                index ==
                                                step.request.dataList.length - 1
                                            "
                                            type="primary"
                                            @click="
                                                addParam(step.request.dataList)
                                            "
                                            >添加</el-button
                                        >
                                        <el-button
                                            v-if="index != 0"
                                            type="danger"
                                            @click="
                                                delParam(
                                                    step.request.dataList,
                                                    index
                                                )
                                            "
                                            >删除</el-button
                                        >
                                    </div>
                                </div>
                                <div v-if="step.paramRadio == 2" id="json">
                                    <div style="display: flex">
                                        <el-select
                                            v-model="aceConfig.theme"
                                            class="m-2"
                                            placeholder="Select">
                                            <el-option
                                                v-for="item in aceConfig.arr"
                                                :key="item"
                                                :label="item"
                                                :value="item" />
                                        </el-select>
                                        <el-button @click="jsonFormat(step)"
                                            >格式化</el-button
                                        >
                                        <el-button @click="jsonNoFormat(step)"
                                            >压缩</el-button
                                        >
                                    </div>

                                    <v-ace-editor
                                        v-model:value="step.request.json"
                                        @init="jsonFormat"
                                        lang="json"
                                        :theme="aceConfig.theme"
                                        :options="aceConfig.options"
                                        :readonly="aceConfig.readOnly"
                                        style="height: 300px; width: 300px"
                                        class="ace-editor" />
                                </div>
                                <div class="params" v-if="step.paramRadio == 3">
                                    <div
                                        class="left"
                                        v-for="(param, index) in step.request
                                            .paramList"
                                        :key="index">
                                        <el-input
                                            v-model="param.name"
                                            style="width: 80px"
                                            placeholder="变量名" />:
                                        <el-input
                                            v-model="param.value"
                                            style="
                                                width: 240px;
                                                margin-right: 5px;
                                            "
                                            placeholder="变量值" />
                                        <el-button
                                            v-if="
                                                index ==
                                                step.request.paramList.length -
                                                    1
                                            "
                                            type="primary"
                                            @click="
                                                addExport(
                                                    step.request.paramList
                                                )
                                            "
                                            >添加</el-button
                                        >
                                        <el-button
                                            v-if="index != 0"
                                            type="danger"
                                            @click="
                                                delParam(
                                                    step.request.paramList,
                                                    index
                                                )
                                            "
                                            >删除</el-button
                                        >
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="list">
                            <div class="title left">参数提取</div>
                            <div
                                class="left li-item"
                                v-for="(extract, index) in step.extractList"
                                :key="index">
                                <li>
                                    <el-input
                                        v-model="extract.name"
                                        style="width: 240px"
                                        placeholder="jmes_path" />:
                                    <el-input
                                        v-model="extract.value"
                                        style="width: 80px; margin-right: 5px"
                                        placeholder="name" />
                                    <el-button
                                        v-if="
                                            index == step.extractList.length - 1
                                        "
                                        type="primary"
                                        @click="addParam(step.extractList)"
                                        >添加</el-button
                                    >
                                    <el-button
                                        type="danger"
                                        @click="
                                            delParam(step.extractList, index)
                                        "
                                        >删除</el-button
                                    >
                                </li>
                            </div>
                            <el-button
                                class="left"
                                v-if="step.extractList.length == 0"
                                type="primary"
                                @click="addParam(step.extractList)"
                                >添加</el-button
                            >
                        </div>
                        <div class="list">
                            <div class="title left">断言</div>
                            <div
                                class="left li-item"
                                v-for="(validate, index) in step.validateList"
                                :key="index">
                                <el-select
                                    style="width: 100px"
                                    v-model="validate.funcName"
                                    placeholder="断言方法">
                                    <el-option
                                        v-for="item in ValidateFunc"
                                        :key="item"
                                        :label="item"
                                        :value="item">
                                    </el-option>
                                </el-select>
                                <el-input
                                    v-model="validate.actual"
                                    style="width: 120px"
                                    placeholder="实际值" />
                                <el-input
                                    v-model="validate.expected"
                                    style="width: 120px"
                                    placeholder="预期值" />
                                <el-input
                                    v-model="validate.msg"
                                    style="width: 150px"
                                    placeholder="失败提示" />
                                <el-button
                                    v-if="index == step.validateList.length - 1"
                                    type="primary"
                                    @click="addValidate(step.validateList)"
                                    >添加</el-button
                                >
                                <el-button
                                    type="danger"
                                    @click="delParam(step.validateList, index)"
                                    >删除</el-button
                                >
                            </div>
                            <el-button
                                class="left"
                                v-if="step.validateList.length == 0"
                                type="primary"
                                @click="addValidate(step.validateList)"
                                >添加</el-button
                            >
                        </div>
                    </el-collapse-item>
                </div>
                <div class="button-container">
                    <div class="but-item">
                        <el-button
                            type="success"
                            :loading="step.status"
                            @click="runStep(step)"
                            >运行</el-button
                        >
                    </div>
                    <div class="but-item" v-if="index == steps.length - 1">
                        <el-button type="primary" @click="addStep(steps)"
                            >添加</el-button
                        >
                    </div>
                    <div class="but-item" v-if="index != 0">
                        <el-button type="danger" @click="delParam(steps, index)"
                            >删除</el-button
                        >
                    </div>
                </div>
            </div>
        </el-collapse>
        <el-drawer
            v-model="drawer"
            title="日志"
            :direction="direction"
            :before-close="handleClose">
            <div v-for="item in responseBody">
                <span style="color: #126436">{{ item.split("|")[0] }}| </span>
                <span
                    :style="
                        item.split('|')[1].includes('DEBUG')
                            ? 'color: #1844c9'
                            : item.split('|')[1].includes('ERROR')
                            ? 'color: #e3402d'
                            : ''
                    "
                    >{{ item.split("|")[1] }}|
                </span>
                <span style="color: #0080c0"
                    >{{ item.split("|")[2].split(" - ")[0] }}|
                </span>
                <span
                    :style="
                        item.split('|')[1].includes('DEBUG')
                            ? 'color: #1844c9'
                            : item.split('|')[1].includes('ERROR')
                            ? 'color: #e3402d'
                            : ''
                    "
                    >{{ item.split("|")[2].split(" - ")[1] }}|
                </span>
            </div>
        </el-drawer>
    </div>
</template>

<script setup>
import { ref, reactive } from "vue";
import { VAceEditor } from "vue3-ace-editor";
import "ace-builds/webpack-resolver";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/theme-chrome";
import "ace-builds/src-noconflict/ext-language_tools";
const caseLoading = ref(false);
const direction = ref("rtl");
const baseUrl = ref("http://127.0.0.1:5000");
const aceConfig = reactive({
    lang: "json", //解析json
    theme: "chrome", //主题
    arr: [
        /*所有主题*/
        "ambiance",
        "chaos",
        "chrome",
        "clouds",
        "clouds_midnight",
        "cobalt",
        "crimson_editor",
        "dawn",
        "dracula",
        "dreamweaver",
        "eclipse",
        "github",
        "gob",
        "gruvbox",
        "idle_fingers",
        "iplastic",
        "katzenmilch",
        "kr_theme",
        "kuroir",
        "merbivore",
        "merbivore_soft",
        "monokai",
        "mono_industrial",
        "pastel_on_dark",
        "solarized_dark",
        "solarized_light",
        "sqlserver",
        "terminal",
        "textmate",
        "tomorrow",
        "tomorrow_night",
        "tomorrow_night_blue",
        "tomorrow_night_bright",
        "tomorrow_night_eighties",
        "twilight",
        "vibrant_ink",
        "xcode",
    ],
    readOnly: false, //是否只读
    options: {
        enableBasicAutocompletion: true,
        enableSnippets: true,
        enableLiveAutocompletion: true,
        tabSize: 2,
        showPrintMargin: false,
        fontSize: 13,
    },
});

const handleClose = (done) => {
    done();
};
const drawer = ref(false);

// JSON格式化
const jsonFormat = (step) => {
    try {
        step.request.json = JSON.stringify(
            JSON.parse(step.request.json),
            null,
            2
        );
    } catch (e) {
        console.log(e);
    }
};

// JSON压缩
const jsonNoFormat = (step) => {
    try {
        step.request.json = JSON.stringify(JSON.parse(step.request.json));
    } catch (e) {
        console.log(e);
    }
};
let responseBody = ref("");

const uploadSuccess = (response, file, fileList) => {
    ElMessage({
        message: "上传成功",
        type: "success",
    });
};

const uploadError = (err, file, fileList) => {
    let errObj = JSON.parse(err.message);
    ElMessage({
        message: errObj.message,
        type: "error",
        plain: true,
    });
};

const runStep = (step) => {
    step.status = true;
    let msg = checkCase(steps.value[0]);
    if (msg != "") {
        ElMessage({
            message: msg,
            type: "error",
            plain: true,
        });
        step.status = false;
        return;
    }
    let data = {
        step: step,
        config: config.value,
    };
    fetch(`${baseUrl.value}/runstep`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
    })
        .then((res) => {
            return res.json();
        })
        .then((res) => {
            drawer.value = true;
            console.log(res);
            responseBody.value = res.logs;
            if (res.status == "success") {
                ElMessage({
                    message: res.message,
                    type: "success",
                });
            } else {
                ElMessage({
                    message: res.message,
                    type: "error",
                    plain: true,
                });
            }
        })
        .catch((err) => {
            ElMessage({
                message: "请求失败",
                type: "error",
                plain: true,
            });
            console.log(err);
        })
        .finally(() => {
            step.status = false;
        });
};

const runCase = () => {
    caseLoading.value = true;
    let msg = checkCase(steps.value[0]);
    if (msg != "") {
        ElMessage({
            message: msg,
            type: "error",
            plain: true,
        });
        caseLoading.value = false;
        return;
    }
    let data = {
        steps: steps.value,
        config: config.value,
    };
    fetch(`${baseUrl.value}/runcase`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
    })
        .then((res) => {
            return res.json();
        })
        .then((res) => {
            drawer.value = true;
            responseBody.value = res.logs;
            if (res.status == "success") {
                ElMessage({
                    message: res.message,
                    type: "success",
                });
            } else {
                ElMessage({
                    message: res.message,
                    type: "error",
                    plain: true,
                });
            }
        })
        .catch((error) => {
            if (error == "TypeError: Failed to fetch") {
                ElMessage({
                    message: "请确认是否已经启动服务端",
                    type: "error",
                    plain: true,
                });
            }
        })
        .finally(() => {
            caseLoading.value = false;
        });
};

const updateConfig = () => {
    let msg = checkCase(steps.value[0]);
    if (msg != "") {
        ElMessage({
            message: msg,
            type: "error",
            plain: true,
        });
        return;
    }
    fetch(`${baseUrl.value}/updateConfig`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(config.value),
    })
        .then((res) => {
            return res.json();
        })
        .then((res) => {
            if (res.status == "success") {
                ElMessage({
                    message: res.message,
                    type: "success",
                });
            } else {
                ElMessage({
                    message: res.message,
                    type: "error",
                    plain: true,
                });
            }
        })
        .catch((error) => {
            if (error == "TypeError: Failed to fetch") {
                ElMessage({
                    message: "请确认是否已经启动服务端",
                    type: "error",
                    plain: true,
                });
            }
        });
};

const checkCase = (step) => {
    if (config.value.name == "") {
        return "请输入测试用例名称";
    }
    if (config.value.base_url == "") {
        return "请输入测试域名";
    }
    if (step.name == "") {
        return "请输入测试步骤名称";
    }
    if (step.request.url == "") {
        return "请输入测试接口地址";
    }
    return "";
};

const downloadYaml = () => {
    let msg = checkCase(steps.value[0]);
    if (msg != "") {
        ElMessage({
            message: msg,
            type: "error",
            plain: true,
        });
        return;
    }
    let data = {
        steps: steps.value,
        config: config.value,
    };
    fetch(`${baseUrl.value}/downloadYaml`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
    })
        .then((response) => {
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.blob(); // 将响应体转换为Blob对象
        })
        .then((blob) => {
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement("a");
            link.href = url;
            link.download = config.value.name + ".yaml"; // 设置下载文件名
            document.body.appendChild(link);
            link.click();
            setTimeout(() => {
                window.URL.revokeObjectURL(url);
                document.body.removeChild(link);
            }, 0);
        })
        .catch((error) => {
            if (error == "TypeError: Failed to fetch") {
                ElMessage({
                    message: "请确认是否已经启动服务端",
                    type: "error",
                    plain: true,
                });
            }
        });
};

const config = ref({
    name: "",
    base_url: "",
    verify: false,
    variableList: [],
    export: [],
});

const MethodOptions = ["GET", "POST"];
const isHttps = [true, false];
const ValidateFunc = ["eq", "neq", "gt", "lt"];
const steps = ref([
    {
        name: "",
        request: {
            url: "",
            method: "GET",
            headerList: [],
            cookieList: [],
            paramList: [{ name: "", value: "" }],
            dataList: [{ name: "", value: "" }],
            json: "",
        },
        variableList: [],
        extractList: [],
        validateList: [],
        paramRadio: 2,
        status: false,
    },
]);
const addStep = (list) => {
    list.push({
        name: "",
        request: {
            url: "",
            method: "GET",
            headerList: [],
            cookieList: [],
            paramList: [{ name: "", value: "" }],
            dataList: [{ name: "", value: "" }],
            json: "",
        },
        variableList: [],
        extractList: [],
        validateList: [],
        paramRadio: 2,
    });
};

const addParam = (list, obj) => {
    list.push({ name: "", value: "" });
};

const delParam = (list, index) => {
    console.log(list);
    list.splice(index, 1);
};

const addExport = (list) => {
    console.log(list);
    list.push("");
};

const addValidate = (list) => {
    list.push({ funcName: "eq", actual: "", expected: "", msg: "" });
};
</script>

<style>
#app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 10px;
}
.but-item {
    margin-right: 5px;
}
.params {
    flex-direction: column;
    width: 500px;
    margin-bottom: 5px;
}
.collapse-item {
    display: flex;
    position: relative;
}
.button-container {
    display: flex;
    position: absolute;
    top: 10px;
    left: 670px; /* 靠近右边 */
}

.collapse-item-container {
    width: 650px;
}
.select-width {
    width: 240px;
}
li {
    list-style-type: none;
}
.li-item {
    margin-bottom: 5px;
}

.item {
    display: flex;
    width: 300px;
    margin-bottom: 5px;
}
.list {
    width: 650px;
    margin-bottom: 10px;
}
.left {
    display: flex;
    justify-content: flex-start;
}
.right {
    margin-right: 5px;
    display: flex;
    justify-content: flex-end;
}
.title {
    width: 100px;
    font-size: 15px;
    margin-bottom: 5px;
}
</style>
